package server.processors;

import java.nio.channels.ClosedChannelException;
import java.util.List;

import server.NetworkMediator;
import server.ServerStateMediator;

import common.Player;
import common.Register;
import common.RegisterResponse;
import common.Round;
import common.Sendable;

public class RegistrationProcessor extends Processor {

	private RegistrationProcessor(NetworkMediator mediator, ServerStateMediator server) {
		super(mediator, server);
	}

	public RegistrationProcessor() {
	}

	@Override
	public Processor getInstanceOf(NetworkMediator mediator, ServerStateMediator server) {
		return new RegistrationProcessor( mediator, server );
	}

	@Override
	public boolean isInterestedIn(Sendable s) {
		return s instanceof Register;
	}

	public void run() {
//		System.out.println("Running the registration processor.");
		NetworkMediator network = getNetwork();
		ServerStateMediator server = getServer();
		
		try {
//			System.out.println("Sending a RegisterResponse to mediator.");
			
			Register reg = (Register) server.getMessage();
			
			
			Player p = server.getClient().player;
			
			if( p != null && p.getRound() != null) {//Error case
//				System.out.println("Player already associated with a round!");
				network.sendTo(p, new RegisterResponse( null ) );
				return;
			}
			
			if( reg.r == null || reg.name == null ) {//Error case
//				System.out.println("Register message is lacking information!");
				network.sendTo(server.getClient(), new RegisterResponse( null ) );
				return;
			}
			

			
			Round round = reg.r; //reg.r is the received round, must find the real one to modify it.
			
			for( Round r : server.getServerState().getAvailableRounds() )
				if( r.equals( round ) ) {
					round = r;
					break;
				}
			
			
			
			List<Player> players = round.getPlayers();
			
			// Lock on the player list to prevent others from modifying the list while iterating over it.
			synchronized( players ) {
				//Check to see if the name is already taken by another player in the round.
				for( Player player : round.getPlayers() )
					if(player.getName().equals( reg.name ) ) {
//						System.out.println("Name is already taken by another player!");
						network.sendTo( server.getClient(), new RegisterResponse( null ) );
						return;
					}
				
				Player newPlayer = new Player( reg.name, null );
				server.registerPlayer( newPlayer );
				
				//Continue to hold lock to ensure that someone else won't try to submit the same name after the uniqueness check
				if( round.addPlayer( newPlayer ) ) {
					network.sendTo( newPlayer, new RegisterResponse( newPlayer ) );
					network.sendToAllClients( round );
				} else {
					//If unable to add the player to the round (because of wrong phase)
					// send them an error register response back.
//					System.out.println("Round is not in registration phase!");
					network.sendTo( newPlayer, new RegisterResponse( null ) );
				}
			}
				
				
			
			
		} catch (ClosedChannelException e) {
			e.printStackTrace();
		}
	}

}
